<template>
  <div>
    <el-form v-if="searchProps.some(v => v.type && v.type !== 'hidden')" ref="queryForm" :model="queryParams" :inline="true" label-width="72px">
      <template v-for="(item, index) in searchProps">
        <el-form-item v-if="item.type !== 'hidden'" :key="index" :label="item.label" :prop="item.prop">
          <el-input
            v-if="item.type === 'input'"
            v-model="queryParams[item.prop]"
            :placeholder="item.placeholder || `请输入${item.label}`"
            :style="{width: item.width ? item.width+'px' : 'auto' }"
            clearable
            size="small"
            @keyup.enter="reload"
          />
          <el-select
            v-if="item.type === 'select'"
            v-model="queryParams[item.prop]"
            :placeholder="item.placeholder || `-- 请选择${item.label} --`"
            clearable
            size="small"
            :style="{width: item.width ? item.width+'px' : 'auto' }"
            @change="reload"
          >
            <el-option
              v-for="dict in item.options"
              :key="dict.value"
              :label="dict.label"
              :value="dict.value"
            />
          </el-select>
          <el-cascader
            v-if="item.type === 'cascader'"
            v-model="queryParams[item.prop]"
            :style="{width: item.width ? item.width+'px' : 'auto' }"
            :placeholder="item.placeholder || `-- 请选择${item.label} --`"
            :options="item.options"
            filterable
            clearable
            size="small"
            :props="item.props"
            @change="reload"
          />
        </el-form-item>
      </template>
      <el-form-item>
        <el-button type="primary" :icon="Search" size="small" @click="reload">搜索</el-button>
      </el-form-item>
    </el-form>
    <el-table ref="table" v-loading="loading" :data="tableData" @row-click="handleRowClick">
      <el-table-column width="50">
        <template #default="scope">
          <input
            v-if="isSingle"
            type="radio"
            :name="inputName"
            :value="scope.row[valueProp]"
            :checked="defaultValue.value === scope.row[valueProp]"
          >
          <input
            v-else
            type="checkbox"
            :name="inputName"
            :value="scope.row[valueProp]"
            v-bind="{
              onclick: defaultValue.value.some(v => v === scope.row[valueProp]) && !actualIsCancel.value ? 'return false;' : '',
              checked: defaultValue.value.some(v => v === scope.row[valueProp]),
              disabled: selectableMethod ? selectableMethod(scope.row) || false : false
            }"
          >
        </template>
      </el-table-column>
      <slot name="default" />
    </el-table>
    <pagination
      v-show="isPage && total > 0"
      :total="total"
      v-model:page="queryParams.pageIndex"
      v-model:limit="queryParams.pageSize"
      @pagination="getData"
    />
  </div>
</template>

<script setup>
import { guid } from "@/utils/index.js"
import { Search } from "@element-plus/icons-vue"

const props = defineProps({
  // 请求数据方法
  loadDataApi: {
    type: String,
    required: true
  },
  // 是否单选
  isSingle: {
    type: Boolean,
    default: true
  },
  // 选择后是否可以取消
  isCancel: {
    type: Boolean,
    default: undefined
  },
  // 值对应的属性名， 一般为id
  valueProp: {
    type: String,
    default: 'id'
  },
  // 是否懒加载
  lazyLoad: {
    type: Boolean,
    default: false
  },
  // 是否为分页数据
  isPage: {
    type: Boolean,
    default: true
  },
  // 搜索框内容
  searchProps: {
    type: Array,
    default: () => []
  },
  // 后端请求下来的数据处理函数
  handleData: {
    type: Function,
    default: null
  },
  // 绑定值
  modelValue: {
    type: [String, Array],
    default: null
  },
  selectableMethod: {
    type: Function,
    default: null
  }
})

const emit = defineEmits(['update:modelValue', 'change'])

const actualIsCancel = computed(() => {
  return props.isCancel ?? !props.isSingle
})

const defaultValue = computed(() => {
  return props.modelValue ?? (props.isSingle ? '' : [])
})

const inputName = ref(guid(16))
// 是否首次加载
const firstLoaded = ref(false)
// 请求参数
const queryParams = ref({
  pageIndex: 1,
  pageSize: 10
})
// 加载状态
const loading = ref(false)
// 数据总数
const total = ref(0)
// 数据
const tableData = ref([])
// 当前单选选中数据
const singleValue = ref('')
// 多选选中数据
const multipleValue = ref([])
const multiples = ref([])

watch(() => props.searchProps, (newVal) => {
  newVal.map(item => {
    queryParams.value[item.prop] = item.default
  })
}, {immediate: true, deep: true})

onMounted(() => {
  if (!props.lazyLoad) {
    reload()
  }
})

function load() {
  if (!firstLoaded.value) {
    queryParams.value.pageIndex = 1
    getData()
  }
}

function reload(newMultiples) {
  firstLoaded.value = false
  multiples.value = newMultiples || []
  load()
}

function getData() {
  loading.value = true
  $xl.apis[props.loadDataApi]({
    params: queryParams.value
  }).then(res => {
    loading.value = false
    firstLoaded.value = true
    if (props.handleData) {
      (props.isPage ? res.data.records : res.data).forEach((v, i) => props.handleData(v, i))
    }
    tableData.value = props.isPage ? res.data.records : res.data
    total.value = res.data?.total || 0
  }).catch(() => {
    loading.value = false
    tableData.value = []
    total.value = 0
  })
}

function handleRowClick(row) {
  if (props.selectableMethod && props.selectableMethod(row)) return
  if (props.isSingle) {
    if (defaultValue.value && defaultValue.value === row[props.valueProp]) {
      if (actualIsCancel.value) {
        singleValue.value = ''
        emit('update:modelValue', singleValue.value)
        emit('change', undefined)
      }
    } else {
      singleValue.value = row[props.valueProp]
      emit('change', row)
      emit('update:modelValue', singleValue.value)
    }
  } else {
    if (defaultValue.value.some(v => v === row[props.valueProp])) {
      if (actualIsCancel.value) {
        multipleValue.value = defaultValue.value.filter(v => v !== row[props.valueProp])
        emit('update:modelValue', multipleValue.value)
        multiples.value = multiples.value.filter(v => v[props.valueProp] !== row[props.valueProp])
        emit('change', multiples.value, row)
      }
    } else {
      multipleValue.value = [...defaultValue.value, row[props.valueProp]]
      emit('update:modelValue', multipleValue.value)
      multiples.value = [...multiples.value, row]
      emit('change', multiples.value, row)
    }
  }
}
</script>
